/*
    SUSAN® - Sole of Unix Save ANything

   Copyright (C) 2013-2014 Skyatlas Co. CN
   

   
*/

#ifndef BAREOS_FILED_ACCURATE_H_
#define BAREOS_FILED_ACCURATE_H_

/*
 * Generic accurate payload is the same for any storage class.
 *
 * We store the lstat field as a character field as it makes storing of the
 * data much more efficient than storing it in a normal stat structure.
 * Nowadays most of these structures are 64 bits and they will use 136
 * bytes (32 bits) and 128 bytes (64 bits) on Solaris. The ASCII encoding
 * of the lstat field most of the time is between 43 and 75 bytes with an
 * average of 60 bytes. (From live data of 152562393 files.)
 *
 * The seen flag is not in the actual accurate payload but stored in a
 * bitmap. This makes it much more efficient for a storage engine that has
 * to update the whole data when something changes. For things like a in
 * memory hash table it doesn't make much difference and it has the
 * disadvantage that we need to keep a filenr to index the bitmap which
 * also cost some bytes.
 */

#include "include/config.h"

#ifdef HAVE_HPUX_OS
#pragma pack(push, 4)
#endif

namespace filedaemon {

struct accurate_payload {
  int64_t filenr;
  int32_t delta_seq;
  char* lstat;
  char* chksum;
};


/*
 * Accurate payload storage abstraction classes.
 */
class BareosAccurateFilelist {
 protected:
  int64_t filenr_ = 0;
  char* seen_bitmap_ = nullptr;
  JobControlRecord* jcr_ = nullptr;
  uint32_t number_of_previous_files_ = 0;

 public:
  BareosAccurateFilelist() = default;
  virtual ~BareosAccurateFilelist() {}

  virtual bool init() = 0;
  virtual bool AddFile(char* fname,
                       int fname_length,
                       char* lstat,
                       int lstat_length,
                       char* chksum,
                       int checksum_length,
                       int32_t delta_seq) = 0;
  virtual bool EndLoad() = 0;
  virtual accurate_payload* lookup_payload(char* fname) = 0;
  virtual bool UpdatePayload(char* fname, accurate_payload* payload) = 0;
  virtual bool SendBaseFileList() = 0;
  virtual bool SendDeletedList() = 0;
  void MarkFileAsSeen(accurate_payload* payload)
  {
    SetBit(payload->filenr, seen_bitmap_);
  }

  void UnmarkFileAsSeen(accurate_payload* payload)
  {
    ClearBit(payload->filenr, seen_bitmap_);
  }

  void MarkAllFilesAsSeen() { SetBitRange(0, filenr_ - 1, seen_bitmap_); }

  void UnmarkAllFilesAsSeen() { ClearBitRange(0, filenr_ - 1, seen_bitmap_); }
};

/*
 * Hash table specific storage abstraction class using the internal htable
 * datastructure.
 */
struct CurFile {
  hlink link;
  char* fname;
  accurate_payload payload;
};

#ifdef HAVE_HPUX_OS
#pragma pack(pop)
#endif

class BareosAccurateFilelistHtable : public BareosAccurateFilelist {
 protected:
  htable* file_list_;
  void destroy();

 public:
  /* methods */
  BareosAccurateFilelistHtable() = delete;
  BareosAccurateFilelistHtable(JobControlRecord* jcr, uint32_t number_of_files);
  ~BareosAccurateFilelistHtable() { destroy(); }

  bool init() override { return true; }

  bool AddFile(char* fname,
               int fname_length,
               char* lstat,
               int lstat_length,
               char* chksum,
               int checksum_length,
               int32_t delta_seq) override;
  bool EndLoad() override;
  accurate_payload* lookup_payload(char* fname) override;
  bool UpdatePayload(char* fname, accurate_payload* payload) override;
  bool SendBaseFileList() override;
  bool SendDeletedList() override;
};

#ifdef HAVE_LMDB

#include "lmdb/lmdb.h"

/*
 * Lightning Memory DataBase (LMDB) specific storage abstraction class using the
 * Symas LMDB.
 */
class BareosAccurateFilelistLmdb : public BareosAccurateFilelist {
 protected:
  int pay_load_length_;
  POOLMEM* pay_load_;
  POOLMEM* lmdb_name_;
  MDB_env* db_env_;
  MDB_dbi db_dbi_;
  MDB_txn* db_rw_txn_;
  MDB_txn* db_ro_txn_;

  void destroy();

 public:
  /* methods */
  BareosAccurateFilelistLmdb() = delete;
  BareosAccurateFilelistLmdb(JobControlRecord* jcr, uint32_t number_of_files);
  ~BareosAccurateFilelistLmdb() { destroy(); }
  bool init() override;
  bool AddFile(char* fname,
               int fname_length,
               char* lstat,
               int lstat_length,
               char* chksum,
               int checksum_length,
               int32_t delta_seq) override;
  bool EndLoad() override;
  accurate_payload* lookup_payload(char* fname) override;
  bool UpdatePayload(char* fname, accurate_payload* payload) override;
  bool SendBaseFileList() override;
  bool SendDeletedList() override;
};
#endif /* HAVE_LMDB */

bool AccurateFinish(JobControlRecord* jcr);
bool AccurateCheckFile(JobControlRecord* jcr, FindFilesPacket* ff_pkt);
bool AccurateMarkFileAsSeen(JobControlRecord* jcr, char* fname);
bool accurate_unMarkFileAsSeen(JobControlRecord* jcr, char* fname);
bool AccurateMarkAllFilesAsSeen(JobControlRecord* jcr);
bool accurate_unMarkAllFilesAsSeen(JobControlRecord* jcr);
void AccurateFree(JobControlRecord* jcr);


} /* namespace filedaemon */
#endif /* BAREOS_FILED_ACCURATE_H_ */
